-- Display all red on a VGA monitor.
-- Copyright James McGill, 2010 (jmcgill@plexer.net)

library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.numeric_std.all;

entity vga is
  port(clk25     : in std_logic;
       reset     : in std_logic;
	    red_in    : in std_logic;
       red_out   : out std_logic;
       green_out : out std_logic;
       blue_out  : out std_logic;
       hs_out    : out std_logic;
       vs_out    : out std_logic;
		 hframe    : out std_logic;
		 vframe    : out std_logic);
end vga;

architecture Behavioural of vga is

-- Horizontal timing values, all in pixel units. Note that the front and back
-- porches include the right and left borders respectively.
constant horizontal_front_porch : integer := 24;
constant horizontal_sync : integer := 56;
constant horizontal_back_porch : integer := 124;
constant horizontal_frame : integer := 640;

 ---- Vertical timing values, all in pixel units. 
constant vertical_frame : integer := 1024;
constant vertical_front_porch : integer := 1;
constant vertical_sync : integer := 3;
constant vertical_back_porch : integer := 38;

signal horizontal_counter : unsigned(15 downto 0) := to_unsigned(0, 16);
signal vertical_counter   : unsigned(15 downto 0) := to_unsigned(0, 16);

begin

process (clk25, reset) 
begin
  if clk25'event and clk25 = '1' then
    if reset = '1' then
      horizontal_counter <= to_unsigned(0, 16);
      vertical_counter <= to_unsigned(0, 16);
      red_out <= '0';
      blue_out <= '0';
      green_out <= '0';
		hs_out <= '1';
		vs_out <= '1';
	 else
      -- One horizontal output looks like this:
      -- [video] [front porch] [hsync] [back porch]
		red_out <= '0';
		green_out <= '0';
		blue_out <= '0';
		
      -- Only output color during video frame and within vertical range.
      if (vertical_counter < vertical_frame) then
        if (horizontal_counter < horizontal_frame) then
	    	  red_out <= red_in;
	  	  end if;
		end if;
		
      -- Issue a horizontal sync pulse at the end of each horizontal frame. 
      -- TODO(jmcgill): Should this be at the START of the frame? 
      if (horizontal_counter >= (horizontal_frame + horizontal_front_porch) and
          horizontal_counter < (horizontal_frame + horizontal_front_porch +
          horizontal_sync)) then
        hs_out <= '0';
      else
        hs_out <= '1';
      end if;

      -- Issue a horizontal sync pulse at the end of each vertical frame. 
      if (vertical_counter >= (vertical_frame + vertical_front_porch) and 
          vertical_counter < (vertical_frame + vertical_front_porch +
          vertical_sync)) then
        vs_out <= '0';
      else
        vs_out <= '1';
      end if;

     -- Reset the horizontal counter at the end of each line.
     -- NOTE(jmcgill): -1 because we index from 0.
     if (horizontal_counter = (horizontal_frame + horizontal_front_porch +
         horizontal_back_porch + horizontal_sync) - 1) then
       horizontal_counter <= to_unsigned(0, 16);
		 
	    -- Reset the vertical counter at the end of the frame.
       if (vertical_counter = (vertical_frame + vertical_front_porch +
           vertical_back_porch + vertical_sync) - 1) then
         vertical_counter <= to_unsigned(0, 16);
		 else
		   vertical_counter <= vertical_counter + 1;
       end if;  
     else
	    horizontal_counter <= horizontal_counter + 1;
	  end if;
    end if;
  end if;	 
end process;

vframe <= '1' when vertical_counter < vertical_frame else
          '0';

hframe <= '1' when horizontal_counter < horizontal_frame else
          '0';
          
end Behavioural;
